package com.zzedu.manager.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tencent.soe.OralEvaluationResponse;
import com.zzedu.common.enums.CommonEnums;
import com.zzedu.common.enums.UserTypeEnumns;
import com.zzedu.common.utils.SecurityUtils;
import com.zzedu.domain.*;
import com.zzedu.dto.subject.WordItemDTO;
import com.zzedu.enmuns.ConfigEnums;
import com.zzedu.enmuns.InteractionTypeEnums;
import com.zzedu.enmuns.SubjectTypeEnums;
import com.zzedu.framework.lock.IDistributedLockService;
import com.zzedu.framework.transaction.ITransactionHandlerService;
import com.zzedu.integration.oss.dto.FileInfoDTO;
import com.zzedu.integration.tencentcloudspeech.ISpeechService;
import com.zzedu.integration.yzs.IYzsService;
import com.zzedu.manager.IZzExerciseBookManager;
import com.zzedu.result.Result;
import com.zzedu.result.ResultEnum;
import com.zzedu.service.*;
import com.zzedu.stu.req.SubmitExerciseBook;
import com.zzedu.system.service.ISysConfigService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class ZzExerciseBookManagerImpl implements IZzExerciseBookManager {

    private static final Logger log = LoggerFactory.getLogger(ZzExerciseBookManagerImpl.class);
    @Autowired
    IZzExerciseBookSubmitContentService zzExerciseBookSubmitContentService;

    @Autowired
    IZzExerciseBookService zzExerciseBookService;

    @Autowired
    IZzPictureNodeService zzPictureNodeService;

    @Autowired
    IZzClassesService zzClassesService;

    @Autowired
    IZzSubjectContentService zzSubjectContentService;

    @Autowired
    IZzStudentService zzStudentService;

    @Autowired
    ITransactionHandlerService transactionHandlerService;

    @Autowired
    IDistributedLockService distributedLockService;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    IZzUploadFileService zzUploadFileService;

    @Autowired
    IZzThesaurusWordsService zzThesaurusWordsService;

    @Autowired
    IYzsService yzsService;

    @Autowired
    ISpeechService speechService;

    @Autowired
    ISysConfigService sysConfigService;

    @Autowired
    IZzClassesSendStudentService zzClassesSendStudentService;

    @Override
    public Result submit(SubmitExerciseBook data) {

        ZzSubjectContent zzSubjectContent = zzSubjectContentService.getById(data.getId());
        if (null == zzSubjectContent) {
            Result result = new Result<>();
            result.setResultCode(ResultEnum.FAIL.getCode());
            result.setResultMessage("题目信息不存在");
            return result;
        }

        if (SecurityUtils.isTeacher()) {
            Result result = new Result<>();
            result.setResultCode(ResultEnum.SUCCESS.getCode());
            result.setResultMessage(ResultEnum.SUCCESS.getDesc());
            result.setData(data.getId());
            InteractionTypeEnums interactionTypeEnums = InteractionTypeEnums.getCode(zzSubjectContent.getInteraction());
            if (InteractionTypeEnums.dub == interactionTypeEnums) {
                JSONObject rspData = new JSONObject();
                rspData.put("id", data.getId());
                resolverSubmitData(result, zzSubjectContent, data, "L0");
                rspData.put("automaticScoring", result.getData());
                result.setData(rspData);
            }
            return result;
        }

        String lockName = "submit:requestSubmitExerciseBook:" + data.getId() + ":" + SecurityUtils.getUserId();
        ZzStudent zzStudent = this.zzStudentService.getById(SecurityUtils.getUserId());
        if (null == zzStudent || (null != zzStudent.getValidTo() && LocalDateTime.now().isAfter(zzStudent.getValidTo()))) {
            Result result = new Result<>();
            result.setResultCode(ResultEnum.FAIL.getCode());
            result.setResultMessage("当前学员已过期");
            return result;
        }

        ZzPictureNode pZzPictureNode;
        ZzClassesSendStudent zzClassesSendStudent;
        if (null != zzSubjectContent.getNodeId()) {
            ZzPictureNode zzPictureNode = zzPictureNodeService.getById(zzSubjectContent.getNodeId());
            if (null != zzPictureNode) {
                pZzPictureNode = zzPictureNodeService.getById(zzPictureNode.getpNodeId());
                if (null != pZzPictureNode) {
                    zzClassesSendStudent = zzClassesSendStudentService.getOne(Wrappers.lambdaQuery(ZzClassesSendStudent.class)
                            .eq(ZzClassesSendStudent::getStuId, SecurityUtils.getUserId())
                            .eq(ZzClassesSendStudent::getBookId, pZzPictureNode.getPictureBookId())
                            .last("limit 1")
                    );
                } else {
                    zzClassesSendStudent = null;
                }
            } else {
                pZzPictureNode = null;
                zzClassesSendStudent = null;
            }
        } else {
            pZzPictureNode = null;
            zzClassesSendStudent = null;
        }
        if (pZzPictureNode == null || null == zzClassesSendStudent) {
            Result result = new Result<>();
            result.setResultCode(ResultEnum.FAIL.getCode());
            result.setResultMessage("题目配置信息错误");
            return result;
        }
        String level = "L0";
        ZzClasses zzClasses = this.zzClassesService.getById(zzClassesSendStudent.getClzzId());
        if (null != zzClasses) {
            level = zzClasses.getLevel();
        }
        Long stuId = SecurityUtils.getUserId();
        Result res = distributedLockService.executeWithLock(lockName, 10L, 30L, TimeUnit.SECONDS, () -> transactionHandlerService.runInTransaction(() -> {
            ZzExerciseBookSubmitContent zzExerciseBookSubmitContent = new ZzExerciseBookSubmitContent();
            zzExerciseBookSubmitContent.setContent(data.getContent());
            zzExerciseBookSubmitContent.setSubmitContent(data.getAnswer());
            zzExerciseBookSubmitContent.setSubjectContent(data.getSubjectContent());
            zzExerciseBookSubmitContentService.save(zzExerciseBookSubmitContent);
            ZzExerciseBook zzExerciseBook = new ZzExerciseBook();

            zzExerciseBook.setNodeId(zzSubjectContent.getNodeId());

            zzExerciseBook.setClazzId(zzClassesSendStudent.getClzzId());


            zzExerciseBook.setContentId(data.getId());
            zzExerciseBook.setStudentId(stuId);
            zzExerciseBook.setSubmitCount(1);
            zzExerciseBook.setCorrectState(1);
            zzExerciseBook.setPictureBookId(pZzPictureNode.getPictureBookId());
            if (null == data.getVideoTime()) {
                data.setVideoTime(0L);
            }
            if (null == data.getRemainTime()) {
                data.setRemainTime(0L);
            }

            zzExerciseBook.setVideoTime(data.getVideoTime());
            zzExerciseBook.setRemainTime(data.getRemainTime());

            zzExerciseBook.setCorrectCount(0);
            zzExerciseBook.setErrorCount(0);


            //需要批改的题目  配音题
            InteractionTypeEnums interaction = InteractionTypeEnums.getCode(zzSubjectContent.getInteraction());
            if (InteractionTypeEnums.dub == interaction && null != zzClassesSendStudent) {
                zzExerciseBook.setCorrectState(0);
                zzExerciseBook.setCorrectTeacherId(zzClassesSendStudent.getTeacherId());
            }
            ZzExerciseBook queryZzExerciseBook = null;
            if ((queryZzExerciseBook = zzExerciseBookService.getOne(Wrappers.lambdaUpdate(ZzExerciseBook.class).eq(ZzExerciseBook::getStudentId, SecurityUtils.getUserId()).eq(ZzExerciseBook::getContentId, data.getId()))) != null) {
                if (null == queryZzExerciseBook.getSubmitCount()) {
                    queryZzExerciseBook.setSubmitCount(0);
                }
                if (null == queryZzExerciseBook.getVideoTime()) {
                    queryZzExerciseBook.setVideoTime(0L);
                }
                if (null == queryZzExerciseBook.getRemainTime()) {
                    queryZzExerciseBook.setRemainTime(0L);
                }
                zzExerciseBook.setId(queryZzExerciseBook.getId());
                zzExerciseBook.setSubmitCount(queryZzExerciseBook.getSubmitCount() + 1);
                zzExerciseBook.setVideoTime(queryZzExerciseBook.getVideoTime() + data.getVideoTime());
                zzExerciseBook.setRemainTime(queryZzExerciseBook.getRemainTime() + data.getRemainTime());
                zzExerciseBook.setCorrectCount(queryZzExerciseBook.getCorrectCount());
                zzExerciseBook.setErrorCount(queryZzExerciseBook.getErrorCount());
                if (null != data.getAnswerResult()) {
                    if (data.getAnswerResult()) {
                        zzExerciseBook.setCorrectCount(queryZzExerciseBook.getCorrectCount() + 1);
                    } else {
                        zzExerciseBook.setErrorCount(queryZzExerciseBook.getErrorCount() + 1);
                    }
                }
            } else {
                if (null != data.getAnswerResult()) {
                    if (data.getAnswerResult()) {
                        zzExerciseBook.setCorrectCount(1);
                    } else {
                        zzExerciseBook.setErrorCount(1);
                    }
                }
            }
            SubjectTypeEnums subjectTypeEnums = SubjectTypeEnums.getCode(zzSubjectContent.getSubjectType());
            if (null != interaction) {
                zzExerciseBook.setCalcFlag(interaction.isCalcFlag() ? CommonEnums.YES.getCode() : CommonEnums.NO.getCode());
            }
            if (SubjectTypeEnums.video == subjectTypeEnums || SubjectTypeEnums.image == subjectTypeEnums) {
                zzExerciseBook.setCalcFlag(CommonEnums.YES.getCode());
            }

            zzExerciseBook.setSubmitId(zzExerciseBookSubmitContent.getId());
            if (null == queryZzExerciseBook) {
                zzExerciseBookService.save(zzExerciseBook);
            } else {
                zzExerciseBookService.updateById(zzExerciseBook);
            }
            zzExerciseBookSubmitContent.setBookId(zzExerciseBook.getId());
            zzExerciseBookSubmitContentService.updateById(zzExerciseBookSubmitContent);
            setCache(data.getId(), zzExerciseBook.getId());
            Result result = new Result<>();
            result.setResultCode(ResultEnum.SUCCESS.getCode());
            result.setResultMessage(ResultEnum.SUCCESS.getDesc());
            result.setData(zzExerciseBook.getId());
            return result;
        }));
        if (!res.getResultCode().equals(ResultEnum.SUCCESS.getCode())) {
            return res;
        }
        JSONObject rspData = new JSONObject();
        rspData.put("id", res.getData());
        InteractionTypeEnums interactionTypeEnums = InteractionTypeEnums.getCode(zzSubjectContent.getInteraction());
        if (InteractionTypeEnums.dub == interactionTypeEnums) {
            resolverSubmitData(res, zzSubjectContent, data, level);
            rspData.put("automaticScoring", res.getData());
        }
        res.setData(rspData);
        return res;
    }


    private void resolverSubmitData(Result result, ZzSubjectContent zzSubjectContent, SubmitExerciseBook data, String level) {
        InteractionTypeEnums interactionTypeEnums = InteractionTypeEnums.getCode(zzSubjectContent.getInteraction());
        if (InteractionTypeEnums.dub == interactionTypeEnums) {
            JSONObject answer = JSON.parseObject(data.getAnswer());
            JSONObject content = JSON.parseObject(data.getContent());
            JSONObject config = JSON.parseObject(sysConfigService.selectConfigByKeyCache(ConfigEnums.AI_SCORE_CONFIG.getCode()));
            if (null == config) {
                config = new JSONObject();
            }
            if (null != content && content.containsKey("content")) {
                if (null != answer) {
                    JSONObject subjectContent = content.getJSONObject("content");
                    List<String> sentences = subjectContent.getList("sentences",String.class);

                    List<WordItemDTO> wordItemDTOList = subjectContent.getList("wordsList", WordItemDTO.class);
                    if (CollectionUtils.isNotEmpty(wordItemDTOList)||CollectionUtils.isNotEmpty(sentences)) {
                        WordItemDTO wordItemDTO = null;
                        if(CollectionUtils.isNotEmpty(wordItemDTOList)){
                            wordItemDTO = wordItemDTOList.get(0);
                        }
                        if(CollectionUtils.isNotEmpty(sentences)){
                            wordItemDTO = new WordItemDTO();
                            wordItemDTO.setWord(sentences.get(0));

                        }

                        JSONArray jsonArray = answer.getJSONArray("answer");
                        if (null != jsonArray) {
                            int size = jsonArray.size();
                            for (int i = 0; i < size; i++) {
                                JSONObject jsonObject = jsonArray.getJSONObject(i);
                                ZzUploadFile zzUploadFile = zzUploadFileService.getById(MapUtils.getLong(jsonObject, "uploadId", -1L));
                                if (null != zzUploadFile) {
                                    FileInfoDTO fileInfoDTO = new FileInfoDTO();
                                    fileInfoDTO.setOriginalFilename(zzUploadFile.getOldFileName());
                                    fileInfoDTO.setFileId(zzUploadFile.getId());
                                    fileInfoDTO.setNewFileName(zzUploadFile.getFileName());
                                    fileInfoDTO.setFileSuffix(zzUploadFile.getFileExt());
                                    fileInfoDTO.setUrl(zzUploadFile.getUrl());
                                    // 1-云知声  2-腾讯
                                    int model = MapUtils.getInteger(config, "model", 0);
                                    if (1 == model) {
                                        result.setData(yzsService.automaticScoring(fileInfoDTO, wordItemDTO.getWord(), SecurityUtils.getUserId() + "_" + data.getId() + "_" + System.currentTimeMillis(), MapUtils.getLong(config, "callTimeout", 6L), MapUtils.getLong(config, "connectTimeout", 6L), MapUtils.getLong(config, "readTimeout", 6L)));
                                    } else if (2 == model) {
                                        OralEvaluationResponse oralEvaluationResponse = speechService.processStream(fileInfoDTO, wordItemDTO.getWord(), SecurityUtils.getUserId() + "_" + data.getId() + "_" + System.currentTimeMillis(), MapUtils.getLong(config, "callTimeout", 6L), MapUtils.getLong(config, "connectTimeout", 6L), MapUtils.getLong(config, "readTimeout", 6L)
                                                , MapUtils.getDouble(config, "tencent_score_" + level, 1.0)
                                        );
                                        if (null != oralEvaluationResponse && 0 == oralEvaluationResponse.getCode()) {
                                            JSONObject obj = new JSONObject();
                                            obj.put("score", oralEvaluationResponse.getResult().getSuggestedScore());
                                            obj.put("info", oralEvaluationResponse);
                                            result.setData(obj);
                                        } else {
                                            result.setData(null);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    public String buildCacheKey() {
        String redisKey = "subject:" + UserTypeEnumns.STUDENT.getCode() + ":userId:" + SecurityUtils.getUserId();
        return redisKey;
    }

    public String buildFiledKey(Long id) {
        return String.valueOf(id);
    }

    private void setCache(Long contentId, Long id) {
        try {
            String redisKey = this.buildCacheKey();
            String filedKey = this.buildFiledKey(contentId);
            redisTemplate.opsForHash().put(redisKey, filedKey, id);
            redisTemplate.expire(redisKey, 90, TimeUnit.DAYS);
        } catch (Exception e) {
            log.error("提交作业,设置setCache error", e.getMessage());
        }
    }
}
